/*
 * Copyright 2007 National Bioinformatics Network
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * 
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package queryexecute;

import java.util.HashMap;
import java.util.Map;

import dgbgui.command.CommandStack;
import dgbgui.command.ResultCommand;
import dgbgui.modeldocument.QueryResult;


public class QueryDistributor {
    
    public static QueryDistributor getInstance() {
        if ( m_instance == null ) {
            m_instance = new QueryDistributor();
        }
        return m_instance;
    }
    
    // Private for singleton
    private QueryDistributor() {
        m_queryStringToExecutors = new HashMap<String,QueryExecutor>();
    }
    
    // Add a query to be distributed
    synchronized public void runQuery(String queryString) {
        // The query could not have been submitted already. 
        // TODO: When a query caching system has been implemented, include this 
        // assert
        //assert(!hasBeenSubmitted(queryString));
        // Create a new query executor for the query string
        //QueryExecutor newExecutor = new LazyStockExecutor(queryString);
        QueryExecutor newExecutor = new CorbaExecutor(queryString);
        // Add the executor to the map
        m_queryStringToExecutors.put(queryString, newExecutor);
        // Run it, but continue in this thread
        newExecutor.start();
    }
    
    
    /**
     * Check whether the query has been submitted
     * return true if the query has already been submitted
     */
    synchronized public boolean hasBeenSubmitted(String queryString) {
        return m_queryStringToExecutors.containsKey(queryString);
    }
    
    /**
     * Check whether a result exists for the query
     * @return true if the result exists
     */
    synchronized public boolean hasResult(String queryString) {
        // The query must have been submitted
        assert(hasBeenSubmitted(queryString));
        // Get the executor
        QueryExecutor executor =  m_queryStringToExecutors.get(queryString);
        return executor.hasResult();
    }
    
    /** 
     * Get the result for a certain query string
     *  @return The result string
     */
    synchronized public QueryResult getResult(String queryString) {
        // The result must exist before getting it.
        assert (hasResult(queryString));
        return m_queryStringToExecutors.get(queryString).getResult();
    }
    
    /**
     * Called by the executor to notify that a result has been obtained.
     * Must be syncronized since it can be called from N threads
     * TODO: Replace with the observer pattern
     */
    synchronized public void resultObtained(QueryExecutor executor) {
        // Create a new result received command
        ResultCommand command = new ResultCommand(executor.getQueryString(),executor.getResult());
        CommandStack.getInstance().execute(command);
        
    }
        
    /// A map of query strings to the query executores
    Map<String,QueryExecutor> m_queryStringToExecutors;
    
    static QueryDistributor m_instance;

}
